#!/usr/bin/env tsx

/**
 * 生产环境构建脚本
 * 编译 TypeScript 代码并创建生产就绪的构建包
 */

import * as fs from 'fs';
import * as path from 'path';
import { execSync } from 'child_process';

interface BuildConfig {
  sourceDir: string;
  outputDir: string;
  entryPoint: string;
  includeAssets: string[];
  excludePatterns: string[];
}

const buildConfig: BuildConfig = {
  sourceDir: 'src',
  outputDir: 'dist',
  entryPoint: 'src/production-server.ts',
  includeAssets: [
    'models/**/*.yml',
    'models/**/*.yaml',
    'config/**/*.json',
    'package.json',
    'README.md'
  ],
  excludePatterns: [
    '**/*.test.ts',
    '**/*.spec.ts',
    '**/tests/**',
    '**/test/**',
    '**/__tests__/**',
    '**/debug-*.js',
    '**/test-*.ts'
  ]
};

function log(message: string, type: 'info' | 'success' | 'error' | 'warn' = 'info'): void {
  const icons = {
    info: '📋',
    success: '✅',
    error: '❌',
    warn: '⚠️'
  };
  console.log(`${icons[type]} ${message}`);
}

function executeCommand(command: string, description: string): void {
  try {
    log(`执行: ${description}`);
    execSync(command, { stdio: 'inherit', cwd: process.cwd() });
    log(`完成: ${description}`, 'success');
  } catch (error) {
    log(`失败: ${description}`, 'error');
    throw error;
  }
}

function ensureDirectoryExists(dirPath: string): void {
  if (!fs.existsSync(dirPath)) {
    fs.mkdirSync(dirPath, { recursive: true });
    log(`创建目录: ${dirPath}`);
  }
}

function cleanOutputDirectory(): void {
  if (fs.existsSync(buildConfig.outputDir)) {
    log(`清理输出目录: ${buildConfig.outputDir}`);
    fs.rmSync(buildConfig.outputDir, { recursive: true, force: true });
  }
  ensureDirectoryExists(buildConfig.outputDir);
}

function copyAssets(): void {
  log('复制资源文件...');
  
  buildConfig.includeAssets.forEach(pattern => {
    try {
      // 使用简单的文件复制逻辑
      if (pattern.includes('**')) {
        // 处理通配符模式
        const baseDir = pattern.split('/**')[0];
        if (fs.existsSync(baseDir)) {
          const targetDir = path.join(buildConfig.outputDir, baseDir);
          ensureDirectoryExists(targetDir);
          executeCommand(`cp -r ${baseDir}/* ${targetDir}/`, `复制 ${pattern}`);
        }
      } else {
        // 处理单个文件
        if (fs.existsSync(pattern)) {
          const targetPath = path.join(buildConfig.outputDir, pattern);
          ensureDirectoryExists(path.dirname(targetPath));
          fs.copyFileSync(pattern, targetPath);
          log(`复制文件: ${pattern} -> ${targetPath}`);
        }
      }
    } catch (error) {
      log(`复制资源失败: ${pattern}`, 'warn');
    }
  });
}

function createProductionPackageJson(): void {
  log('创建生产环境 package.json...');
  
  const originalPackage = JSON.parse(fs.readFileSync('package.json', 'utf8'));
  
  const productionPackage = {
    name: originalPackage.name,
    version: originalPackage.version,
    description: originalPackage.description,
    type: 'module',
    main: 'production-server.js',
    scripts: {
      start: 'node production-server.js',
      'health-check': 'curl -f http://localhost:${PORT:-3000}/health || exit 1'
    },
    dependencies: {
      // 只包含生产依赖
      ...Object.fromEntries(
        Object.entries(originalPackage.dependencies || {})
          .filter(([name]) => !name.includes('test') && !name.includes('dev'))
      )
    },
    engines: originalPackage.engines,
    author: originalPackage.author,
    license: originalPackage.license
  };
  
  fs.writeFileSync(
    path.join(buildConfig.outputDir, 'package.json'),
    JSON.stringify(productionPackage, null, 2)
  );
  
  log('生产环境 package.json 创建完成', 'success');
}

function createDockerfile(): void {
  log('创建 Dockerfile...');
  
  const dockerfile = `# 生产环境 Dockerfile
FROM node:18-alpine

# 设置工作目录
WORKDIR /app

# 复制 package.json 和 package-lock.json
COPY package*.json ./

# 安装生产依赖
RUN npm ci --only=production && npm cache clean --force

# 复制构建后的应用代码
COPY . .

# 创建非 root 用户
RUN addgroup -g 1001 -S nodejs && \
    adduser -S dslorm -u 1001

# 设置文件权限
RUN chown -R dslorm:nodejs /app
USER dslorm

# 暴露端口
EXPOSE 3000

# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
  CMD npm run health-check

# 启动应用
CMD ["npm", "start"]
`;
  
  fs.writeFileSync(path.join(buildConfig.outputDir, 'Dockerfile'), dockerfile);
  log('Dockerfile 创建完成', 'success');
}

function createDockerIgnore(): void {
  log('创建 .dockerignore...');
  
  const dockerignore = `node_modules
npm-debug.log
.git
.gitignore
README.md
.env
.nyc_output
coverage
.nyc_output
*.md
`;
  
  fs.writeFileSync(path.join(buildConfig.outputDir, '.dockerignore'), dockerignore);
  log('.dockerignore 创建完成', 'success');
}

function createStartupScript(): void {
  log('创建启动脚本...');
  
  const startupScript = `#!/bin/bash

# 生产环境启动脚本
# 设置默认环境变量
export NODE_ENV=\${NODE_ENV:-production}
export PORT=\${PORT:-3000}
export LOG_LEVEL=\${LOG_LEVEL:-info}

# 验证必需的环境变量
if [ -z "$NODE_ENV" ]; then
  echo "❌ NODE_ENV 环境变量未设置"
  exit 1
fi

echo "🚀 启动 DSL ORM 生产服务器"
echo "环境: $NODE_ENV"
echo "端口: $PORT"
echo "日志级别: $LOG_LEVEL"

# 启动应用
exec node production-server.js
`;
  
  fs.writeFileSync(path.join(buildConfig.outputDir, 'start.sh'), startupScript);
  fs.chmodSync(path.join(buildConfig.outputDir, 'start.sh'), '755');
  log('启动脚本创建完成', 'success');
}

function validateBuild(): void {
  log('验证构建结果...');
  
  const requiredFiles = [
    'src/production-server.js',
    'package.json',
    'Dockerfile',
    'start.sh'
  ];
  
  const missingFiles = requiredFiles.filter(file => 
    !fs.existsSync(path.join(buildConfig.outputDir, file))
  );
  
  if (missingFiles.length > 0) {
    log(`缺少必需文件: ${missingFiles.join(', ')}`, 'error');
    throw new Error('构建验证失败');
  }
  
  log('构建验证通过', 'success');
}

async function buildProduction(): Promise<void> {
  try {
    log('🏗️  开始生产环境构建', 'info');
    log('========================');
    
    // 1. 清理输出目录
    cleanOutputDirectory();
    
    // 2. 编译 TypeScript
    executeCommand('npx tsc --project tsconfig.json --outDir dist', 'TypeScript 编译');
    
    // 3. 复制资源文件
    copyAssets();
    
    // 4. 创建生产环境配置文件
    createProductionPackageJson();
    createDockerfile();
    createDockerIgnore();
    createStartupScript();
    
    // 5. 验证构建
    validateBuild();
    
    log('🎉 生产环境构建完成!', 'success');
    log('========================');
    log(`📦 构建输出: ${buildConfig.outputDir}`);
    log('🐳 Docker 构建: docker build -t dsl-orm-server .');
    log('🚀 本地运行: cd dist && npm install --production && npm start');
    
  } catch (error) {
    log('构建失败', 'error');
    console.error(error);
    process.exit(1);
  }
}

// 如果直接运行此脚本，则开始构建
if (import.meta.url === `file://${process.argv[1]}`) {
  buildProduction();
}

export { buildProduction, BuildConfig };